const express = require('express');
const http = require('http');
const WebSocket = require('ws');

const app = express();
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });

// Store game state
const games = new Map();
const players = new Map();
let playerIdCounter = 1;
let gameIdCounter = 1;

// Serve static files
app.use(express.static('public'));

// Handle WebSocket connections
wss.on('connection', (ws) => {
  const playerId = playerIdCounter++;
  players.set(playerId, { ws, gameId: null, symbol: null });
  
  console.log(`Player ${playerId} connected`);
  
  // Send player ID to client
  ws.send(JSON.stringify({ type: 'playerId', playerId }));
  
  ws.on('message', (message) => {
    try {
      const data = JSON.parse(message);
      
      switch (data.type) {
        case 'findGame':
          findGame(playerId);
          break;
          
        case 'makeMove':
          makeMove(playerId, data.position);
          break;
          
        case 'rematch':
          rematch(playerId);
          break;
          
        default:
          ws.send(JSON.stringify({ type: 'error', message: 'Unknown message type' }));
      }
    } catch (error) {
      console.error('Error parsing message:', error);
      ws.send(JSON.stringify({ type: 'error', message: 'Invalid message format' }));
    }
  });
  
  ws.on('close', () => {
    const player = players.get(playerId);
    if (player && player.gameId) {
      const game = games.get(player.gameId);
      if (game) {
        // Notify the other player that their opponent disconnected
        const otherPlayerId = game.players.find(id => id !== playerId);
        if (otherPlayerId) {
          const otherPlayer = players.get(otherPlayerId);
          if (otherPlayer && otherPlayer.ws.readyState === WebSocket.OPEN) {
            otherPlayer.ws.send(JSON.stringify({
              type: 'opponentDisconnected'
            }));
          }
        }
        
        // Remove the game
        games.delete(player.gameId);
      }
    }
    
    // Remove the player
    players.delete(playerId);
    console.log(`Player ${playerId} disconnected`);
  });
});

function findGame(playerId) {
  const player = players.get(playerId);
  if (!player) return;
  
  // Try to find an existing game with a waiting player
  for (const [gameId, game] of games) {
    if (game.players.length === 1 && !game.started) {
      // Join this game
      game.players.push(playerId);
      game.started = true;
      
      // Assign symbols
      const player1 = players.get(game.players[0]);
      const player2 = players.get(game.players[1]);
      
      player1.symbol = 'X';
      player2.symbol = 'O';
      
      player.gameId = gameId;
      player1.gameId = gameId;
      
      // Notify players that the game starts
      player1.ws.send(JSON.stringify({
        type: 'gameStart',
        symbol: player1.symbol,
        yourTurn: true
      }));
      
      player2.ws.send(JSON.stringify({
        type: 'gameStart',
        symbol: player2.symbol,
        yourTurn: false
      }));
      
      return;
    }
  }
  
  // No existing game found, create a new one
  const gameId = gameIdCounter++;
  const game = {
    id: gameId,
    players: [playerId],
    started: false,
    board: Array(9).fill(null),
    currentPlayer: 'X'
  };
  
  games.set(gameId, game);
  player.gameId = gameId;
  
  // Notify player they are waiting
  player.ws.send(JSON.stringify({
    type: 'waitingForOpponent'
  }));
}

function makeMove(playerId, position) {
  const player = players.get(playerId);
  if (!player || !player.gameId) return;
  
  const game = games.get(player.gameId);
  if (!game || !game.started) return;
  
  // Check if it's the player's turn
  if (player.symbol !== game.currentPlayer) {
    player.ws.send(JSON.stringify({
      type: 'error',
      message: 'Not your turn'
    }));
    return;
  }
  
  // Check if position is valid
  if (position < 0 || position > 8 || game.board[position] !== null) {
    player.ws.send(JSON.stringify({
      type: 'error',
      message: 'Invalid move'
    }));
    return;
  }
  
  // Make the move
  game.board[position] = player.symbol;
  
  // Check for win or draw
  const result = checkGameResult(game.board);
  
  // Notify both players
  const player1 = players.get(game.players[0]);
  const player2 = players.get(game.players[1]);
  
  const message = {
    type: 'moveMade',
    position,
    symbol: player.symbol,
    board: game.board,
    result
  };
  
  if (player1 && player1.ws.readyState === WebSocket.OPEN) {
    player1.ws.send(JSON.stringify({
      ...message,
      yourTurn: player1.symbol !== player.symbol && !result
    }));
  }
  
  if (player2 && player2.ws.readyState === WebSocket.OPEN) {
    player2.ws.send(JSON.stringify({
      ...message,
      yourTurn: player2.symbol !== player.symbol && !result
    }));
  }
  
  // Switch turns if game continues
  if (!result) {
    game.currentPlayer = game.currentPlayer === 'X' ? 'O' : 'X';
  }
}

function rematch(playerId) {
  const player = players.get(playerId);
  if (!player || !player.gameId) return;
  
  const game = games.get(player.gameId);
  if (!game) return;
  
  // Check if game has ended (either win or draw)
  const result = checkGameResult(game.board);
  if (!result) {
    // Game is still in progress, cannot request rematch
    player.ws.send(JSON.stringify({
      type: 'error',
      message: 'Game is still in progress, cannot request rematch'
    }));
    return;
  }
  
  // Check if both players want a rematch
  if (!game.rematchRequests) {
    game.rematchRequests = [];
  }
  
  // Add player to rematch requests if not already there
  if (!game.rematchRequests.includes(playerId)) {
    game.rematchRequests.push(playerId);
  }
  
  // If both players requested rematch
  if (game.rematchRequests.length === 2) {
    // Reset game state
    game.board = Array(9).fill(null);
    game.currentPlayer = 'X';
    delete game.rematchRequests;
    
    // Notify players
    const player1 = players.get(game.players[0]);
    const player2 = players.get(game.players[1]);
    
    if (player1 && player1.ws.readyState === WebSocket.OPEN) {
      player1.ws.send(JSON.stringify({
        type: 'rematchAccepted',
        yourTurn: player1.symbol === 'X'
      }));
    }
    
    if (player2 && player2.ws.readyState === WebSocket.OPEN) {
      player2.ws.send(JSON.stringify({
        type: 'rematchAccepted',
        yourTurn: player2.symbol === 'X'
      }));
    }
  } else {
    // Notify the other player that rematch was requested
    const otherPlayerId = game.players.find(id => id !== playerId);
    const otherPlayer = players.get(otherPlayerId);
    
    if (otherPlayer && otherPlayer.ws.readyState === WebSocket.OPEN) {
      otherPlayer.ws.send(JSON.stringify({
        type: 'rematchRequested'
      }));
    }
  }
}

function checkGameResult(board) {
  // Check for win
  const winPatterns = [
    [0, 1, 2], [3, 4, 5], [6, 7, 8], // rows
    [0, 3, 6], [1, 4, 7], [2, 5, 8], // columns
    [0, 4, 8], [2, 4, 6]             // diagonals
  ];
  
  for (const pattern of winPatterns) {
    const [a, b, c] = pattern;
    if (board[a] && board[a] === board[b] && board[a] === board[c]) {
      return { winner: board[a], pattern };
    }
  }
  
  // Check for draw
  if (board.every(cell => cell !== null)) {
    return { draw: true };
  }
  
  // Game continues
  return null;
}

// 改为
const PORT = process.env.PORT || 3000;  // 或者 443（如果使用HTTPS）
server.listen(PORT, '0.0.0.0', () => {
  console.log(`Server is listening on port ${PORT}`);
});